package ywh.utils
{
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.net.URLRequest;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;
	import ywh.utils.event.LoadersPoolEvent;
	
	/**
	 * 单例类
	 * @author 杨伟华
	 */
	public class RSLLoader extends EventDispatcher
	{
		private var _activeloaders:Vector.<Loader>;
		private var _usableLoaders:Vector.<Loader>;
		private var _maxLoaderCount:uint = 1;
		private var _loadqueue:Array;
		private var _loaderContext:LoaderContext;
		static private var _$:RSLLoader;
		private var _initFun:Function;
		
		public function RSLLoader(p:PrivateClass)
		{
			if (!p || _$)
			{
				throw(new Error("RSLLoader是一个单例类，请调用RSLLoader.$"));
			}
			else
			{
				_$ = this;
			}
			_activeloaders = new Vector.<Loader>();
			_usableLoaders = new Vector.<Loader>();
			_loadqueue = [];
			_loaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
		}
		static private function get $():RSLLoader {
			return _$ || new RSLLoader(new PrivateClass());
		}
		static public function get maxLoaderCount():uint
		{
			return $.instanceMaxLoaderCount;
		}
		
		static public function set maxLoaderCount(value:uint):void
		{
			$.instanceMaxLoaderCount = value;
		}
		
		static public function addRSL(url:String, isInsert:Boolean = false):void
		{
			$.addToLoad(url, isInsert);
		}
		
		static public function addEventListener(type:String, fun:Function):void
		{
			$.addEventListener(type, fun);
		}
		
		static public function setInitFun(fun:Function):void
		{
			$.setInitFun(fun);
		}
		
		private function setInitFun(fun:Function):void
		{
			_initFun = fun;
		}
		/* DELEGATE ywh.utils.RSLLoader */
		
		protected function get instanceMaxLoaderCount():uint
		{
			return _maxLoaderCount;
		}
		
		protected function set instanceMaxLoaderCount(value:uint):void
		{
			_maxLoaderCount = value;
		}
		
		protected function addToLoad(url:String, isInsert:Boolean = false):void
		{
			
			var loader:Loader = getLoader();
			if (loader)
			{
				dispatchPoolEvent(LoadersPoolEvent.LOAD_BEGIN);
				loader.load(new URLRequest(url), _loaderContext);
			}
			else
			{
				dispatchPoolEvent(LoadersPoolEvent.LOAD_ADD_TO_QUEUE);
				_loadqueue.push(url);
			}
		}
		
		private function makeLoader():Loader
		{
			var loader:Loader = new Loader();
			loader.contentLoaderInfo.addEventListener(Event.INIT, loader_init);
			loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, loader_ioError);
			loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, loader_progress);
			return loader;
		}
		
		private function getLoader():Loader
		{
			if (_activeloaders.length < _maxLoaderCount)
			{
				var loader:Loader = (_usableLoaders.pop() || makeLoader());
				_activeloaders.push(loader);
				return loader;
			}
			else
			{
				return null;
			}
		}
		
		private function loader_init(e:Event):void
		{
			dispatchPoolEvent(LoadersPoolEvent.LOAD_FINISH);
			var loader:Loader = (e.target as LoaderInfo).loader;
			if (_loadqueue.length)
			{
				dispatchPoolEvent(LoadersPoolEvent.LOAD_BEGIN);
				loader.load(new URLRequest(_loadqueue.shift()), _loaderContext);
			}
			else
			{
				dispatchPoolEvent(LoadersPoolEvent.LOAD_QUEUE_IS_EMPTY);
				_activeloaders.splice(_activeloaders.indexOf(loader), 1);
				_usableLoaders.push(loader);
				if (_activeloaders.length == 0)
				{
					dispatchPoolEvent(LoadersPoolEvent.LOAD_ALL_FINISH);
					_initFun();
				}
			}
		}
		
		private function loader_progress(e:ProgressEvent):void
		{
			this.dispatchEvent(e);
		}
		
		private function loader_ioError(e:IOErrorEvent):void
		{
			throw new Error((e.target as LoaderInfo).url + "模块加载错误");
		}
		
		private function dispatchPoolEvent(type:String):void
		{
			this.dispatchEvent(new LoadersPoolEvent(type));
		}
	}
}

class PrivateClass
{
}